﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Media;

namespace ttg_internal.Utilities.PipelineManager.Diagram.Controls
{
    public class ConnectionPathHelper : FrameworkElement
    {
        // Dependency properties
        public static readonly DependencyProperty SourceRectProperty = DependencyProperty.Register("SourceRect", typeof(Rect), typeof(ConnectionPathHelper), new PropertyMetadata(OnInputPropertyChanged));
        public static readonly DependencyProperty TargetRectProperty = DependencyProperty.Register("TargetRect", typeof(Rect), typeof(ConnectionPathHelper), new PropertyMetadata(OnInputPropertyChanged));
        
        private static readonly DependencyPropertyKey ArrowStartPropertyKey = DependencyProperty.RegisterReadOnly("ArrowStart", typeof(Point), typeof(ConnectionPathHelper), new PropertyMetadata());
        public static readonly DependencyProperty ArrowStartProperty = ArrowStartPropertyKey.DependencyProperty;

        private static readonly DependencyPropertyKey ArrowEndPropertyKey = DependencyProperty.RegisterReadOnly("ArrowEnd", typeof(Point), typeof(ConnectionPathHelper), new PropertyMetadata());
        public static readonly DependencyProperty ArrowEndProperty = ArrowEndPropertyKey.DependencyProperty;

        public Rect SourceRect
        {
            get { return (Rect)GetValue(SourceRectProperty); }
            set { SetValue(SourceRectProperty, value); }
        }

        public Rect TargetRect
        {
            get { return (Rect)GetValue(TargetRectProperty); }
            set { SetValue(TargetRectProperty, value); }
        }

        public Point ArrowStart
        {
            get { return (Point)GetValue(ArrowStartProperty); }
            private set { SetValue(ArrowStartPropertyKey, value); }
        }

        public Point ArrowEnd
        {
            get { return (Point)GetValue(ArrowEndProperty); }
            private set { SetValue(ArrowEndPropertyKey, value); }
        }

        private void CalculateArrowPoints()
        {
            var connectingLine = new LineGeometry(SourceRect.Center(), TargetRect.Center());
            ArrowStart = connectingLine.GetIntersectionPoints(new RectangleGeometry(SourceRect)).SingleOrDefault();
            ArrowEnd = connectingLine.GetIntersectionPoints(new RectangleGeometry(TargetRect)).SingleOrDefault();
        }

        private static void OnInputPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Debug.Assert(d is ConnectionPathHelper);
            ((ConnectionPathHelper)d).CalculateArrowPoints();
        }
    }

    internal static class GeometryHelper
    {
        public static Point Center(this Rect rect)
        {
            return rect.TopLeft + new Vector(rect.Width / 2, rect.Height / 2);
        }

        public static IEnumerable<Point> GetIntersectionPoints(this Geometry g1, Geometry g2)
        {
            Geometry og1 = g1.GetWidenedPathGeometry(new Pen(Brushes.Black, 1.0));
            Geometry og2 = g2.GetWidenedPathGeometry(new Pen(Brushes.Black, 1.0));

            var cg = new CombinedGeometry(GeometryCombineMode.Intersect, og1, og2);

            PathGeometry pg = cg.GetFlattenedPathGeometry();

            return pg.Figures.Select(t => new PathGeometry(new[] { t }).Bounds)
                .Select(fig => new Point(fig.Left + fig.Width / 2.0, fig.Top + fig.Height / 2.0));
        }
    }
}
